package com.szwistar.common.datastruct;

import com.j256.ormlite.field.DataPersister;
import com.j256.ormlite.field.FieldType;
import com.j256.ormlite.field.SqlType;
import com.j256.ormlite.support.DatabaseResults;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * 用于将复杂类型字段以 JSON 字符串的形式持久化到数据库中
 * <p>它适用于比较简单的单次解析就可以完成的字段。
 * <p>对于更复杂的、需要多次解析的字段，可以使用 {@link JsonableType}
 */
public class JsonFieldPersister implements DataPersister {
	static final Logger LOG = LoggerFactory.getLogger(JsonFieldPersister.class);

	// 单实例
	static final JsonFieldPersister singleton = new JsonFieldPersister();
	// 获取单实例：DataPersister 的实现类必须提供此函数！
	public static JsonFieldPersister getSingleton() { return singleton; }

	@Override public SqlType getSqlType() { return SqlType.STRING; }
	@Override public int getDefaultWidth() { return 255; }
	@Override public boolean isPrimitive() { return false; }
	@Override public boolean isStreamType() { return false; }

	@Override public Class<?> getPrimaryClass() { return null; }
	@Override public Object parseDefaultString(FieldType fieldType, String defaultStr) throws SQLException { return null; }
	@Override public Object resultStringToJava(FieldType fieldType, String stringValue, int columnPos) throws SQLException { return null; }
	@Override public Class<?>[] getAssociatedClasses() { return null; }
	@Override public String[] getAssociatedClassNames() { return null; }
	@Override public Object makeConfigObject(FieldType fieldType) throws SQLException { return null; }
	@Override public Object convertIdNumber(Number number) { return null; }
	@Override public boolean isValidForField(Field field) { return false; }
	@Override public boolean isEscapedDefaultValue() { return false; }
	@Override public boolean isEscapedValue() { return false; }
	@Override public boolean isComparable() { return false; }
	@Override public boolean isAppropriateId() { return false; }
	@Override public boolean isArgumentHolderRequired() { return false; }
	@Override public boolean isSelfGeneratedId() { return false; }
	@Override public boolean isValidGeneratedType() { return false; }
	@Override public Object generateId() { return null; }
	@Override public boolean dataIsEqual(Object obj1, Object obj2) { return false; }
	@Override public boolean isValidForVersion() { return false; }
	@Override public Object moveToNextValue(Object currentValue) throws SQLException { return null; }
	@Override public String getSqlOtherType() { return null; }

	@Override
	public Object javaToSqlArg(FieldType fieldType, Object obj) throws SQLException {
		try {
			String json = JsonMapper.toJson(obj);
			return json;
		} catch (Exception e) {
			throw new SQLException(e);
		}
	}

	@Override
	public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) throws SQLException {
		return sqlArg;
	}

	@Override
	public Object resultToSqlArg(FieldType fieldType, DatabaseResults results, int columnPos) throws SQLException {
		return null;
	}

	@Override
	public Object resultToJava(FieldType fieldType, DatabaseResults results, int columnPos) throws SQLException {
		String json = results.getString(columnPos);
		Field field = fieldType.getField();
		Class<?> type = field.getType();
		Type gtype = field.getGenericType();

		try {
			// 如果目标类名是 List 或 Map，则需要取得元素的类型
			if(gtype instanceof GenericArrayType) {
				GenericArrayType aType = (GenericArrayType) gtype;
				Class<?> valueType = (Class<?>) aType.getGenericComponentType();

				//LOG.debug("加载表字段 '{}.{}' 到 '{}.{} (类型为 {}[]) ...'",
				//	fieldType.getTableName(), fieldType.getColumnName(),
				//	field.getDeclaringClass().getSimpleName(), field.getName(),
				//	valueType.getSimpleName());

				// 先解析为 ArrayList
				ArrayList<?> ret = JsonMapper.fromJsonAsListOf(json, valueType);
				// 再转化为数组返回
				return ret.toArray();
			}
			else if(Utils.isAssignableFrom(type, ArrayList.class)) {
				ParameterizedType pType = (ParameterizedType) gtype;
				Class<?> valueType = (Class<?>) pType.getActualTypeArguments()[0];

				//Class<?> rawType = (Class<?>) pType.getRawType();
				//LOG.debug("加载表字段 '{}.{}' 到 '{}.{} (类型为 {}<{}>) ...'",
				//	fieldType.getTableName(), fieldType.getColumnName(),
				//	field.getDeclaringClass().getSimpleName(), field.getName(),
				//	rawType.getSimpleName(),
				//	valueType.getSimpleName());

				// 解析为 ArrayList
				Object ret = JsonMapper.fromJsonAsListOf(json, valueType);
				return ret;
			}
			else if(Utils.isAssignableFrom(type, HashMap.class)) {
				ParameterizedType pType = (ParameterizedType) gtype;
				Class<?> keyType = (Class<?>) pType.getActualTypeArguments()[0];
				Class<?> valueType = (Class<?>) pType.getActualTypeArguments()[1];

				//Class<?> rawType = (Class<?>) pType.getRawType();
				//LOG.debug("加载表字段 '{}.{}' 到 '{}.{} (类型为 {}<{}, {}>) ...'",
				//	fieldType.getTableName(), fieldType.getColumnName(),
				//	field.getDeclaringClass().getSimpleName(), field.getName(),
				//	rawType.getSimpleName(),
				//	keyType.getSimpleName(),
				//	valueType.getSimpleName());

				// 解析为 HashMap
				Object ret = JsonMapper.fromJsonAsMapOf(json, keyType, valueType);
				return ret;
			}
			else {
				// 由 JsonMapper 自动解析
				Object ret = JsonMapper.fromJson(json, type);
				return ret;
			}
		} catch (Exception e) {
			throw new SQLException(e);
		}
	}
}
